using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

using Xfinity.Engine;
using Xfinity.Engine.Plugins;
using Xfinity.Settings;

namespace Xfinity.Console
{
    /// <summary>
    /// Some default basic commands.
    /// </summary>
    public static class DefaultCommands
    {
        /// <summary>
        /// Sets the specified property.
        /// </summary>
        /// <param name="commands">The value.</param>
        [BindCommand("set")]
        public static void Set(string[] commands)
        {
            try
            {
                string variableName = commands[1];
                PropertyInfo prop = typeof(EngineSettings).GetProperty(variableName, BindingFlags.Static);
                prop.SetValue(null, GetArguments(commands), null);
            }
            catch (TargetInvocationException)
            {
                StandardConsole.WriteLine("Command usage: set <property> <value>. Note: valid arguments must be supplied.");
            }
        }

        [BindCommand("Exit")]
        public static void Exit(string[] commands)
        {
            GameManager.Game.Exit();
        }


        [BindCommand("LookAt")]
        public static void LookAt(string[] commands)
        {
            try
            {
                float x = float.Parse(commands[1]);
                float y = float.Parse(commands[2]);
                float z = float.Parse(commands[3]);
                Vector3 v = new Vector3(x, y, z);
                System.Diagnostics.Debug.WriteLine(v, "Look at");
                GraphicsHelper.ActiveCamera.LookAt(v);
            }
            catch (FormatException)
            {
                StandardConsole.WriteLine("Command usage: lookat {x} {y} {z}");
            }
            catch (IndexOutOfRangeException)
            {
                StandardConsole.WriteLine("Command usage: lookat {x} {y} {z}");
            }

        }

        [BindCommand("MoveTo")]
        public static void MoveTo(string[] commands)
        {
            try
            {
                float x = float.Parse(commands[1]);
                float y = float.Parse(commands[2]);
                float z = float.Parse(commands[3]);
                Vector3 v = new Vector3(x, y, z);
                System.Diagnostics.Debug.WriteLine(v, "Move to");
                GraphicsHelper.ActiveCamera.Position = v;
            }
            catch (FormatException)
            {
                StandardConsole.WriteLine("Command usage: moveto {x} {y} {z}");
            }
            catch (IndexOutOfRangeException)
            {
                StandardConsole.WriteLine("Command usage: moveto {x} {y} {z}");
            }

        }

        /// <summary>
        /// Binds the specified commands to a key.
        /// </summary>
        /// <param name="commands">The commands.</param>
        [BindCommand("bind")]
        public static void Bind(string[] commands)
        {
            if (commands.Length < 3)
            {
                StandardConsole.WriteLine("Command usage: bind <key> <command>");
                return;
            }
            Keys key = (Keys)Enum.Parse(typeof(Keys),
                                 commands[1],
                                 true);

            string command = GetArguments(commands);

            InputHandler.BindToCommand(key, command);

            System.Diagnostics.Trace.WriteLine("Bound " + key.ToString() + " to " + command);
        }

        /// <summary>
        /// Gets the arguments in string form.
        /// </summary>
        /// <param name="commands">The commands.</param>
        /// <returns></returns>
        private static string GetArguments(string[] commands)
        {
            string command = String.Join(" ", commands, 2, commands.Length - 3);
            return command;
        }


        [BindCommand("ToggleConsole", BoundKey = Keys.OemTilde)]
        public static void ToggleConsole(string[] commands)
        {
            StandardConsole.DefaultConsole.Visible = !StandardConsole.DefaultConsole.Visible;
            StandardConsole.ConsoleShowing = !GraphicsHelper.DrawModels;
            StandardConsole.RedirectInputToConsole = !StandardConsole.RedirectInputToConsole;
        }

        /// <summary>
        /// Toggles the game pause state.
        /// </summary>
        /// <param name="commands">The commands.</param>
        [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "commands", Justification = "This is just the way the delegate is.")]
        [BindCommand("pause")]
        public static void Pause(string[] commands)
        {
            GameManager.Paused = !GameManager.Paused;
        }

        /// <summary>
        /// Changes the player name.
        /// </summary>
        /// <param name="commands">The name.</param>
        [BindCommand("name")]
        public static void ChangeName(string[] commands)
        {
            try
            {
                Properties.Settings.Default.PlayerName = string.Join(" ", commands, 1, commands.Length - 1);
                Properties.Settings.Default.Save();
            }
            catch (ArgumentOutOfRangeException)
            {
                StandardConsole.WriteLine("Command usage: name <player name>.");
            }
        }
    }
}